\chapter{控制【CONTROL】}

\section{内置命令【Built-in Commands】}

GEANT4有丰富的内置用户接口命令，几乎每个命令都对应一个GEANT4类。这些命令可通过以下方式使用：

\begin{itemize}
	\item 通过（图形）用户接口-(G)UI来交互使用；
	\item 在宏文件中通过`/control/execute $<$command$>$'命令来使用；
	\item 通过G4UImanager类中的ApplyCommand方法用C++编程实现。
\end{itemize}
\rule{\textwidth}{1 pt}
\begin{flushleft}
注：个别命令的可用性、参数范围及其参数的可用备选项，会依据你的应用程序的执行而变化，甚至可能在执行任务过程中动态变化。
\end{flushleft}
\rule{\textwidth}{1 pt}
以下是可用命令的简要总结。你也可以通过执行UI交互窗口中的`help'命令来查看所有可用命令。
\begin{itemize}
	\item List of built-in commands
\end{itemize}

\section{用户接口-定义新命令【User Interface - Defining New Commands】}

\subsection{G4UImessenger}

G4UImessenger 是一个基类，它描述了一个将命令传递给目标类对象的messenger。具体messenger则被提供用户接口的功能类所实例化和拥有。信使也可以被这些类在其析构函数中删除。

你的具体messenger应当具备以下功能：

\begin{itemize}
	\item 可以在messenger的构造器中构造你的命令。
	\item 可以在messenger的析构器中销毁你的命令。
\end{itemize}

这些要求意味着你的messenger应当保证所有命令对象的指针都是它的数据成员。

你可以将G4UIcommand的派生类用于常见的命令类型。这些派生类根据它们的类别有其自身的转换方法，并使得Messenger的SetNewValue()和
GetCurrentValue()方法实现起来更加简单容易。

G4UICommand对象由messenger所属，若通过\textit{new}来实例化对象，则它们应当在messenger析构函数中被删除。

对于需要多参数的复杂命令，你可以使用G4UIcommand基类，自己来构建G4UIparameter对象，且你无需自己删除G4UIparameter对象。

In the SetNewValue() and GetCurrentValue() methods of your
messenger, you can compare the G4UIcommand pointer given in the argument of these
methods with the pointer of your command, because your messenger keeps the
pointers to the commands.Thus, you don't need to compare by
command name.Please remember, in the cases where you use
G4UIcommand derived classes, you should store the pointers with the types of
these derived classes so that you can use methods defined in the derived classes
according to their types without casting.

在你的messenger的SetNewValue()和GetCurrentValue()方法中，由于messenger保持由指向命令的指针，你可以比较由这些方法的变量给定的命令指针和该指向命令的指针。因此，你无需通过命令名进行比较。请记住，在你使用G4UIcommand派生类的情况下，你应当用派生类的类型来存储指针，这样便可以根据它们的类型来使用定义在派生类里的方法，而不会导致强制转换类型。

G4UImanager/G4UIcommand/G4UIparameter
有非常强大的类型和范围检查例程。强烈建议你设置参数范围。对于数值类型（int或double）,通过一个C++语法的字符串（G4String）来给定参数范围，例如 ''X$>$ 0 \&\& X $<$ 10''。对于字符串类型，你可以设置备选列表。请参阅以下详细说明。

在相关命令的用户应用之后，SetNewValue()被调用之前，GetCurrentValue() 被调用。该GetCurrentValue()
方法仅在以下情况之一下被调用：

\begin{itemize}
	\item 至少有一个命令参数有取值范围；
	\item 至少一个有命令参数有备选列表；
	\item 至少有一个参数取值被缺省，且该参数被定义为可缺省类型及当前默认值（currentValueAsDefault）。
\end{itemize}

对于前两种情况，如果有必要你可以重设参数范围或备选列表，但这些重设参数也仅在参数范围或备选列表是动态变化的情况下才需要。

一个命令可以是状态敏感的，即该命令只能被确定的G4ApplicationState(s)所接受。例如，当GEANT4正在运行另一个事件时（``G4State\_EventProc''状态），命令`/run/beamOn'不能被接受。你可以使用AvailableForStates()方法来设置命令的可用状态。

\subsection{G4UIcommand和它的派生类【G4UIcommand and its
derived classes】}

\paragraph{所有派生类的可用方法Methods available for all derived classes}

这些定义在G4UIcommand基类中而在其派生类中使用的方法

\begin{itemize}
	\item void SetGuidance(char*)
	
	Define a guidance line. You can invoke this method as many
times as you need to give enough amount of guidance. Please note that the first line will be used as a title head of the command guidance.

定义一条指导语句。你可以按照你所需要指导语句的数量多次调用该方法。请注意，第一行将被作为命令指导语句的标题头。

\item void availableForStates(G4ApplicationState s1,...)

如果你的命令仅对确定状态的GEANT4内核是有效的，通过该方法来明确这些状态。当前有效状态为G4State\_PreInit,，G4State\_Init,，G4State\_Idle，G4State\_GeomClosed，
和 G4State\_EventProc。每种状态的含义请参阅\textbf{状态机（指GEANT4本身）}。

\item void SetRange(char* range)

定义参数范围。使用C++语法，如''x $>$ 0 \&\& x $<$
10''，通过由SetParameterName()方法定义的变量名。
对于G4ThreeVector，你可以设置参数之间的关系，如``x $>$ y''。
\end{itemize}


\paragraph{G4UIdirectory}

This is a G4UIcommand derived class for defining a directory
containing commands. It is owned by, and should be deleted in the destructor of,
the associated G4UImessenger class, after all of its contained commands have been
deleted.

这是一个用来定义包含命令的路径的G4UIcommand派生类。它属于G4UImessenger相关类，且应当在该类的析构器中删除，这样它所包含的所有命令也被删除。
\begin{itemize}
\item G4UIdirectory(char* directoryPath)

Constructor. Argument is (full-path) directory, which must begin and terminate with ``/:.

构造器。 其参数是（绝对）路径，开始和结束都必须使用 ``/:字符。
\end{itemize}


\paragraph{G4UIcmdWithoutParameter}

This is a G4UIcommand derived class for a command which takes no parameter.

这是一个用于定义无参数命名的G4UIcommand派生类。

\begin{itemize}
\item G4UIcmdWithoutParameter(char* commandPath, G4UImessenger*
theMessenger)

Constructor. Arguments are the (full-path) command name and the pointer to your messenger.

构造器。 其参数是（绝对）路径，开始和结束都必须使用 ``/:字符。
\end{itemize}

\begin{itemize}
\item G4UIcmdWithoutParameter(char* commandPath, G4UImessenger*
theMessenger)

Constructor. Arguments are the (full-path) command name and the pointer to your
messenger.

构造器。参数是（全路径）命令名和你的messenger指针。

\end{itemize}

\paragraph{G4UIcmdWithABool}

这是一个带有一个bool类型变量的G4UIcommand派生类。

\begin{itemize}
	\item G4UIcmdWithABool(char* commandpath,G4UImanager* theMessenger)
	
	构造器。参数是（全路径）命令名和你的messenger指针。
	
	\item void SetParameterName(char* paramName, G4bool omittable)
	
	给Boolean类型参数命名，并设置omittable缺省标志。若omittable为真，你应当使用下一方法定义其默认值。
	
	\item void SetDefaultValue(G4bool defVal)
	
	定义Boolean参数的默认值。
	
	\item G4bool GetNewBoolValue(G4String paramString)
	
	将G4String参数值转化为Boolean值。该G4String通过SetNewValue()方法赋值得到。
	
	\item G4String convertToString(G4bool currVal)
	
	将当前Boolean值转换成G4String类型，该G4String被用作你的messenger的GetCurrentValue()方法的返回值。
\end{itemize}


\paragraph{G4UIcmdWithAnInteger}

这是一个带有一个整型参数的G4UIcommand派生类。

\begin{itemize}
	\item G4UIcmdWithAnInteger(char* commandpath, G4UImanager* theMessenger)
	
	构造器。参数是（全路径）命令名和你的messenger指针。
	
	\item void SetParameterName(char* paramName, G4bool omittable)
	
	给整型参数命名，并设置omittable缺省标志。若omittable为真，你应当使用下一方法定义其默认值。
	
	\item void SetDefaultValue(G4int defVal)
	
	定义整型参数的默认值。
	
	\item G4int GetNewIntValue(G4String paramString)
	
	将G4String参数值转化为整型。该G4String通过SetNewValue()方法赋值得到。
	
	\item G4String convertToString(G4int currVal)

将当前整型数值转换成G4String类型，该G4String被用作你的messenger的GetCurrentValue()方法的返回值。
\end{itemize}


\paragraph{G4UIcmdWithADouble}
这是一个带有一个double类型参数的G4UIcommand派生类。

\begin{itemize}
	\item G4UIcmdWithADouble(char* commandpath, G4UImanager* theMessenger)
	
	构造器。参数是（全路径）命令名和你的messenger指针。
	
		\item void SetParameterName(char* paramName, G4bool omittable)
		
		给double类型参数的命名，并设置omittable缺省标志。若omittable为真，你应当使用下一方法定义其默认值。
		
			\item void SetDefaultValue(G4double defVal)
			
			定义double类型参数的默认值
			
	\item G4double GetNewIntValue(G4String paramString)
	
	将G4String参数值转化为double类型。该G4String通过SetNewValue()方法赋值得到。
	
		\item G4String convertToString(G4double currVal)
		
		将当前double类型数值转换成G4String类型，该G4String被用作你的messenger的GetCurrentValue()方法的返回值。
\end{itemize}


\paragraph{G4UIcmdWithAString}

这是一个带有一个字符串类型参数的G4UIcommand派生类。

\begin{itemize}
	\item G4UIcmdWithAString(char* commandpath, G4UImanager* theMessenger)
	
	构造器。参数是（全路径）命令名和你的messenger指针。
	
		\item void SetParameterName(char* paramName, G4bool omittable)
		
	给字符串类型参数命名，并设置omittable缺省标志。若omittable为真，你应当使用下一方法定义其默认值。
	
		\item void SetDefaultValue(char* defVal)
		
	定义字符串类型参数的默认值
	
		\item void SetCandidates(char* candidateList)
		
		定义参数可采用的候选列表。列表中每个候选项应当用一个空格分隔开。若候选列表已经给定，用户给定的不在该候选列表中的字符串将会被拒绝。
		
				
\end{itemize}


\paragraph{G4UIcmdWith3Vector}

这是一个带有一个G4ThreeVector类型参数的G4UIcommand派生类。

\begin{itemize}
	\item G4UIcmdWithA3Vector(char* commandpath, G4UImanager* theMessenger)
	
	构造器。参数是（全路径）命令名和你的messenger指针。
	
	\item void SetParameterName(\label{OLE_LINK27}char* paramNamX, char* paramNamY, char* paramNamZ, G4bool omittable)
	
	给三维矢量类型参数每个分量命名，并设置omittable缺省标志。若omittable为真，你应当使用下一方法定义其默认值。
	
		\item void SetDefaultValue(G4ThreeVector defVal)
		
		定义三维矢量类型参数的默认值。
		
	\item G4ThreeVector GetNewIntValue(G4String paramString)
	
将G4String参数值转换为G4ThreeVector类型。该G4String通过SetNewValue()方法赋值得到。

	\item G4String convertToString(G4ThreeVector currVal)
	
将当前G4ThreeVector类型参数转换成G4String类型，该G4String被用作你的messenger的GetCurrentValue()方法的返回值。
				
		
\end{itemize}


\paragraph{G4UIcmdWithADoubleAndUnit}

这是一个带有一个double类型参数及其单位的G4UIcommand派生类。

\begin{itemize}
	\item G4UIcmdWithADoubleAndUnit(char* commandpath, G4UImanager* theMessenger)
	
	构造器。参数是（全路径）命令名和你的messenger指针。
	
		\item void SetParameterName(char* paramName, G4bool omittable)
		
		给double类型参数命名，并设置omittable缺省标志。若omittable为真，你应当使用下一方法定义其默认值。
		
	\item void SetDefaultValue(G4double defVal)		
	
	定义double类型参数的默认值。
	
\item void SetUnitCategory(char* unitCategory)
		
	定义可接受的单位类别。
	
	\item void SetDefaultUnit(char* defUnit)
	
定义默认的单位。请在本方法与SetUnitCategory()方法中选择一个使用。

		\item G4double GetNewDoubleValue(G4String paramString)
		
	将G4String参数值转换为double类型。该G4String通过SetNewValue()方法赋值得到。		请注意，返回值已经乘了给定的单位值。	
	
		\item G4double GetNewDoubleRawValue(G4String paramString)
		
		将G4String参数值转换为double类型。该G4String通过SetNewValue()方法赋值得到。但是返回值没有乘给定单位值。
		
	\item G4double GetNewUnitValue(G4String paramString)
	
将G4String类型单位值通过messenger的SetNewValue()方法转换成double类型。

	\item G4String convertToString(G4bool currVal, char* unitName)

将当前double类型参数转换成G4String类型，该G4String被用作你的messenger的GetCurrentValue()方法的返回值。该double类型数值会被除以它的单位，然后转换成字符串。给定的单位也加到字符串中。			
\end{itemize}


\paragraph{G4UIcmdWith3VectorAndUnit}

这是一个带有一个G4ThreeVector类型参数及其单位的G4UIcommand派生类。

\begin{itemize}
	\item G4UIcmdWith3VectorAndUnit(char* commandpath, G4UImanager* theMessenger)
	
	构造器。参数是（全路径）命令名和你的messenger指针。
	
	\item void SetParameterName(char* paramNamX, char* paramNamY, char* paramNamZ, G4bool omittable)
	
		给三维矢量类型参数每个分量命名，并设置omittable缺省标志。若omittable为真，你应当使用下一方法定义其默认值。

\item void SetDefaultValue(G4ThreeVector defVal)

定义三维矢量类型参数的默认值。

	\item void SetUnitCategory(char* unitCategory)

定义可接受的单位类别。

	\item void SetDefaultUnit(char* defUnit)
	
定义默认的单位。请在本方法与SetUnitCategory()方法中选择一个使用。

	\item G4ThreeVector GetNew3VectorValue(G4String paramString)
	
将G4String参数值转换为double类型。该G4String通过SetNewValue()方法赋值得到。		请注意，返回值已经乘了给定的单位值。
	
	
		\item G4ThreeVector GetNew3VectorRawValue(G4String paramString)
		
		将G4String参数值转换为三维矢量类型。该G4String通过SetNewValue()方法赋值得到。但是返回值没有乘给定单位值。

	\item G4double GetNewUnitValue(G4String paramString)
	
	将G4String类型单位值通过messenger的SetNewValue()方法转换成double类型。

	\item G4String convertToString(G4ThreeVector currVal, char* unitName)

将当前三维矢量类型参数转换成G4String类型，该G4String被用作你的messenger的GetCurrentValue()方法的返回值。该三维矢量类型数值会被除以它的单位，然后转换成字符串。给定的单位也加到字符串中。	
	
\end{itemize}

\paragraph{SetParameterName() 方法的附加说明}

你可以为上文提到的每个SetParameterName()
方法额外添加一个G4bool类型的参数。此额外参数被命名为currentAsDefaultFlag，且默认值为false。如果你将该额外参数设置为true，则参数的默认值将被目标类的当前值所覆盖。



\subsection{一个messenger的例子【An example messenger】}

这是G4ParticleGunMessenger的例子，它从G4UIcommand继承而来。

\begin{lstlisting}[caption=例子G4ParticleGunMessenger.hh的内容]
#ifndef G4ParticleGunMessenger_h
#define G4ParticleGunMessenger_h 1
class G4ParticleGun;
class G4ParticleTable;
class G4UIcommand;
class G4UIdirectory;
class G4UIcmdWithoutParameter;
class G4UIcmdWithAString;
class G4UIcmdWithADoubleAndUnit;
class G4UIcmdWith3Vector;
class G4UIcmdWith3VectorAndUnit;
#include "G4UImessenger.hh"
#include "globals.hh"
class G4ParticleGunMessenger: public G4UImessenger
{
public:
G4ParticleGunMessenger(G4ParticleGun * fPtclGun);
~G4ParticleGunMessenger();
public:
void SetNewValue(G4UIcommand * command,G4String newValues);
G4String GetCurrentValue(G4UIcommand * command);
private:
G4ParticleGun * fParticleGun;
G4ParticleTable * particleTable;
private: //commands
G4UIdirectory *
gunDirectory;
G4UIcmdWithoutParameter *
listCmd;
G4UIcmdWithAString *
particleCmd;
G4UIcmdWith3Vector *
directionCmd;
G4UIcmdWithADoubleAndUnit * energyCmd;
G4UIcmdWith3VectorAndUnit * positionCmd;
G4UIcmdWithADoubleAndUnit * timeCmd;
};
#endif
\end{lstlisting}

\begin{lstlisting}[caption=例子G4ParticleGunMessenger.cc的内容。]
#include "G4ParticleGunMessenger.hh"
#include "G4ParticleGun.hh"
#include "G4Geantino.hh"
#include "G4ThreeVector.hh"
#include "G4ParticleTable.hh"
#include "G4UIdirectory.hh"
#include "G4UIcmdWithoutParameter.hh"
#include "G4UIcmdWithAString.hh"
#include "G4UIcmdWithADoubleAndUnit.hh"
#include "G4UIcmdWith3Vector.hh"
#include "G4UIcmdWith3VectorAndUnit.hh"
#include <iostream.h>

G4ParticleGunMessenger::G4ParticleGunMessenger(G4ParticleGun * fPtclGun)
:fParticleGun(fPtclGun)
{
particleTable = G4ParticleTable::GetParticleTable();
gunDirectory = new G4UIdirectory("/gun/");
gunDirectory->SetGuidance("Particle Gun control commands.");
listCmd = new G4UIcmdWithoutParameter("/gun/list",this);
listCmd->SetGuidance("List available particles.");
listCmd->SetGuidance(" Invoke G4ParticleTable.");
particleCmd = new G4UIcmdWithAString("/gun/particle",this);
particleCmd->SetGuidance("Set particle to be generated.");
particleCmd->SetGuidance(" (geantino is default)");
particleCmd->SetParameterName("particleName",true);
particleCmd->SetDefaultValue("geantino");
G4String candidateList;
G4int nPtcl = particleTable->entries();
for(G4int i=0;i<nPtcl;i++)
{
candidateList += particleTable->GetParticleName(i);
candidateList += " ";
}
particleCmd->SetCandidates(candidateList);
directionCmd = new G4UIcmdWith3Vector("/gun/direction",this);
directionCmd->SetGuidance("Set momentum direction.");
directionCmd->SetGuidance("Direction needs not to be a unit vector.");
directionCmd->SetParameterName("Px","Py","Pz",true,true);
directionCmd->SetRange("Px != 0 || Py != 0 || Pz != 0");
energyCmd = new G4UIcmdWithADoubleAndUnit("/gun/energy",this);
energyCmd->SetGuidance("Set kinetic energy.");
energyCmd->SetParameterName("Energy",true,true);
energyCmd->SetDefaultUnit("GeV");
energyCmd->SetUnitCandidates("eV keV MeV GeV TeV");
positionCmd = new G4UIcmdWith3VectorAndUnit("/gun/position",this);
positionCmd->SetGuidance("Set starting position of the particle.");
positionCmd->SetParameterName("X","Y","Z",true,true);
positionCmd->SetDefaultUnit("cm");
positionCmd->SetUnitCandidates("micron mm cm m km");
timeCmd = new G4UIcmdWithADoubleAndUnit("/gun/time",this);
timeCmd->SetGuidance("Set initial time of the particle.");
timeCmd->SetParameterName("t0",true,true);
timeCmd->SetDefaultUnit("ns");
timeCmd->SetUnitCandidates("ns ms s");
// Set initial value to G4ParticleGun
fParticleGun->SetParticleDefinition( G4Geantino::Geantino() );
fParticleGun->SetParticleMomentumDirection( G4ThreeVector(1.0,0.0,0.0) );
fParticleGun->SetParticleEnergy( 1.0*GeV );
fParticleGun->SetParticlePosition(G4ThreeVector(0.0*cm, 0.0*cm, 0.0*cm));
fParticleGun->SetParticleTime( 0.0*ns );
}
\end{lstlisting}

\begin{lstlisting}
G4ParticleGunMessenger::~G4ParticleGunMessenger()
{
delete listCmd;
delete particleCmd;
delete directionCmd;
delete energyCmd;
delete positionCmd;
delete timeCmd;
delete gunDirectory;
}

void G4ParticleGunMessenger::SetNewValue(
G4UIcommand * command,G4String newValues)
{
if( command==listCmd )
{ particleTable->dumpTable(); }
else if( command==particleCmd )
{
G4ParticleDefinition* pd = particleTable->findParticle(newValues);
if(pd != NULL)
{ fParticleGun->SetParticleDefinition( pd ); }
}
else if( command==directionCmd )
{ fParticleGun->SetParticleMomentumDirection(directionCmd->
GetNew3VectorValue(newValues)); }
else if( command==energyCmd )
{ fParticleGun->SetParticleEnergy(energyCmd->
GetNewDoubleValue(newValues)); }
else if( command==positionCmd )
{ fParticleGun->SetParticlePosition(
directionCmd->GetNew3VectorValue(newValues)); }
else if( command==timeCmd )
{ fParticleGun->SetParticleTime(timeCmd->
GetNewDoubleValue(newValues)); }
}
G4String G4ParticleGunMessenger::GetCurrentValue(G4UIcommand * command)
{
G4String cv;
if( command==directionCmd )
{ cv = directionCmd->ConvertToString(
fParticleGun->GetParticleMomentumDirection()); }
else if( command==energyCmd )
{ cv = energyCmd->ConvertToString(
fParticleGun->GetParticleEnergy(),"GeV"); }
else if( command==positionCmd )
{ cv = positionCmd->ConvertToString(
fParticleGun->GetParticlePosition(),"cm"); }
else if( command==timeCmd )
{ cv = timeCmd->ConvertToString(
fParticleGun->GetParticleTime(),"ns"); }
else if( command==particleCmd )
{ // update candidate list
G4String candidateList;
G4int nPtcl = particleTable->entries();
for(G4int i=0;i<nPtcl;i++)
{
candidateList += particleTable->GetParticleName(i);
candidateList += " ";
}
particleCmd->SetCandidates(candidateList);
}
return cv;
}
\end{lstlisting}

\subsection{如何控制G4cout/G4cerr的输出【How to control the output of
G4cout/G4cerr】}

GEANT4使用G4cout and G4cerr来替代\textit{std::cout }and
\textit{std::cerr}。G4cout/G4cerr的输出流由G4UImanager来控制，它允许应用程序编程人员控制流的流向。输出字符串从而被显示在另一窗口或存在文件中。通过以下步骤完成:

\begin{enumerate}
\item 从G4UIsession派生类并实施以下两个方法：
\begin{lstlisting}
G4int ReceiveG4cout(const G4String& coutString);
G4int ReceiveG4cerr(const G4String& cerrString);
\end{lstlisting}

这两个方法分别接收G4cout and G4cerr字符串流。 字符串可通过处理满足特定的要求。以下示范代码显示了如何生成一个输出流的日志文件：
\begin{lstlisting}
ostream logFile;
logFile.open("MyLogFile");
G4int MySession::ReceiveG4cout(const G4String& coutString)
{
logFile << coutString << flush;
return 0;
}
\end{lstlisting}

\item 使用G4UImanager::SetCoutDestination(session)方法设置G4cout/G4cerr的输出路径。通常该方法在G4UIsession或其派生类（如G4UIGAG/G4UIteminal）的构造器中被调用的。该方法设置了一个会话（session）的
G4cout/G4cerr目标路径。例如，当下列代码出现在G4UIterminal构造器中，SetCoutDestination(this)
方法会告诉UImanager，G4UIterminal实例接收G4cout产生的流。
\begin{lstlisting}
G4UIterminal::G4UIterminal()
{
UI = G4UImanager::GetUIpointer();
UI->SetCoutDestination(this);
// ...
}
\end{lstlisting}

相似地，UI-$>$SetCoutDestination(NULL) 必须加到类的析构器中.

\item 编写或修改main函数。 修改exampleB1
来产生一个日志文件，如步骤一所述方法派生一个类，\label{OLE_LINK55} 并添加以下内容到 main函数中:

\begin{lstlisting}
#include "MySession.hh"
main()
{
// get the pointer to the User Interface manager
G4UImanager* UI = G4UImanager::GetUIpointer();
// construct a session which receives G4cout/G4cerr
MySession * LoggedSession = new MySession;
UI->SetCoutDestination(LoggedSession);
// session->SessionStart(); // not required in this case
// .... do simulation here ...
delete LoggedSession;
return 0;
}
\end{lstlisting}

\end{enumerate}
\rule{\textwidth}{1 pt}
注：如果一个类实例旨在用作静态类，则G4cout/G4cerr不应当在类的构造器中被使用。该限制来源于C++的语法规范. 详细内容请看以下文档：
\begin{itemize}
	\item M.A.Ellis, B.Stroustrup, ``Annotated C++ Reference Manual'', Section 3.4\textit{[Ellis1990]}
	\item P.J.Plauger, ``The Draft Standard C++ Library''\textit{[Plauger1995]}
\end{itemize}
\rule{\textwidth}{1 pt}
